package cnsatmsmart.automation.mmi.controller.IO;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.TransferHandler;

/**
 * Kelas yang akan melakukan printscreen
 * Gambar yang dihasilkan dapat disalin ke clipboard ataupun disimpan dalam format PNG
 * @author SIK - PTIK, BPPT
 */
public class ImageDriver implements Runnable{

    //Constanta
    /**
     * Menunjukan mode penyimpanan gambar dengan format PNG
     */
    public static final int SAVEASPNG = 1;
    /**
     * Menunjukan mode penyalinan gambar ke clipboard
     */
    public static final int COPYTOCLIPBOARD = 2;

    //Atributtes
    private int Mode;
    private long WaitTime;
    private File FileSelected;
    private String ScreenTitle;
        
    /**
     * Konstruktor untuk mode penyimpanan gambar dengan format PNG
     * @param screenTitle Judul screen yang akan di-printscreen
     * @param fileSelected File yang akan digunakan untuk menyimpan gambar
     * @param waitTime Waktu perkiraan thread untuk menunggu screen telah siap untuk di-printscreen
     */
    public ImageDriver(String screenTitle, File fileSelected, long waitTime)
    {
        this.ScreenTitle = screenTitle;
        this.FileSelected = fileSelected;
        this.Mode = SAVEASPNG;
        this.WaitTime = waitTime;
    }

    /**
     * Konstruktor untuk mode penyalinan gambar ke clipboard
     * @param screenTitle Judul screen yang akan di-printscreen
     * @param waitTime Waktu perkiraan thread untuk menunggu screen telah siap untuk di-printscreen
     */
    public ImageDriver(String screenTitle, long waitTime)
    {
        this.ScreenTitle = screenTitle;
        this.Mode = COPYTOCLIPBOARD;
        this.WaitTime = waitTime;
    }

    /**
     * Fungsi untuk melakukan printscreen layar dengan batas - batas yang telah ditentukan
     * Bagian layar yang akan di-printscreen hanyalah pada bagian map saja
     * @param ScreenTitle Judul screeen yang akan di-printscreen
     * @return Gambar hasil printscreen
     * @throws InterruptedException
     * @throws AWTException
     */
    private BufferedImage PrintScreenMap (String ScreenTitle) throws InterruptedException, AWTException
    {
        Frame[] Frames = Frame.getFrames();
        Frame activeFrame = null;
        
        //Iterasi untuk mendapatkan frame yang diinginkan berdasarkan screen titlenya,
        //frame yang akan di print screen akan di set always on top
        for (int i = 0; i < Frames.length; i++)
        {
            if (Frames[i].getTitle().equals(ScreenTitle))
            {
                Frames[i].setAlwaysOnTop(true);
                activeFrame = Frames[i];
            }
        }

        //Menunggu sampai layar siap untuk di-printscreen
        Thread.sleep(WaitTime);

        //Ukuran dan posisi layar yang akan diprintscreen
        int ScreenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;
        int ScreenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
        int x = (int) (activeFrame.getBounds().x + 0.005 * ScreenWidth);
        int y = (int) (activeFrame.getBounds().y + 0.170 * ScreenHeight);
        int width = (int) (activeFrame.getBounds().width - 0.074 * ScreenWidth);
        int height = (int) (activeFrame.getBounds().height - 0.186 * ScreenHeight);
        Rectangle frameBounds = new Rectangle (x, y, width, height);

        //Menggunakan kelas Robot untuk melakukan printscreen
        Robot robot = new Robot();
        BufferedImage img = robot.createScreenCapture(frameBounds);

        activeFrame.setAlwaysOnTop(false);

        return addText(img);
    }

    /**
     * Fungsi untuk menambahkan teks ke dalam gambar
     * Teks yang ditambahkan adalah keterangan waktu gambar tersebut diambil
     * @param old Gambar awal yang telah di-printscreen
     * @return Gambar hasil printscreen dengan tambahan teks berupa keterangan waktu gambar diambil
     */
    private BufferedImage addText(BufferedImage old) {
        int w = old.getWidth();
        int h = old.getHeight();
        BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = img.createGraphics();
        g2d.drawImage(old, 0, 0, null);
        g2d.setPaint(Color.yellow);
        g2d.setFont(new Font("Courier New", Font.PLAIN, 20));
        String s = getTimeNow();
        FontMetrics fm = g2d.getFontMetrics();
        int x = img.getWidth() - fm.stringWidth(s) - 5;
        int y = img.getHeight() - fm.getHeight();
        g2d.drawString(s, x, y);
        g2d.dispose();
        return img;
    }

    /**
     * Fungsi untuk mendapatkan waktu saat ini
     * @return Waktu saat ini dengan format DD/MM/YYYY HH:MM:SS
     */
    public String getTimeNow()
        {
            Calendar calendar = new GregorianCalendar();

            int date = calendar.get(Calendar.DATE);
            int month = calendar.get(Calendar.MONTH) + 1;
            int year = calendar.get(Calendar.YEAR);
            int hour = calendar.get(Calendar.HOUR);
            int minute = calendar.get(Calendar.MINUTE);
            int second = calendar.get(Calendar.SECOND);

            if(calendar.get(Calendar.AM_PM) != 0) hour+=12;
            String TimeNow = InttoString(date) + "/" + InttoString(month) + "/" + year + " " + InttoString(hour)  + ":" + InttoString(minute) + ":" + InttoString(second);

            return TimeNow;
        }

    /**
     * Fungsi untuk mengubah integer ke String dan menambahkan 0 di depan angka yang < 10
     * Fungsi digunakan pada getTimeNow() agar angka yang < 10 dapat menjadi dua digit
     * @param integer Angka yang akan diubah menjadi String
     * @return Hasil angka yang telah diubah formatnya menjadi String dan ditambahkan 0 didepan apabila < 10
     */
    private String InttoString(int integer){
        String temp = "0";
        if (integer < 10){
            temp += Integer.toString(integer);
        }else{
            temp = Integer.toString(integer);
        }
        return temp;
    }

    /**
     * Prosedur untuk melakukan printscreen layar kemudian menyalin gambar hasilnya ke clipboard
     * @param screenTitle Judul screen yang akan di-printscreen
     * @throws InterruptedException
     * @throws AWTException
     */
    private void copyToClipboard(String screenTitle) throws InterruptedException, AWTException
    {
        BufferedImage img = PrintScreenMap(screenTitle);
        ImageWriter.setClipboard(img);
    }

    /**
     * Prosedur untuk melakukan printscreen layar kemudian menyimpan gambar hasilnya ke sebuah file dengan format PNG
     * @param screenTitle Judul screen yang akan di-printscreen
     * @param selectedFile File yang akan digunakan untuk menyimpan hasil printscreen
     * @throws IOException
     * @throws InterruptedException
     * @throws AWTException
     */
    private void saveAsPNG(String screenTitle, File selectedFile) throws IOException, InterruptedException, AWTException
    {
        BufferedImage img = PrintScreenMap(screenTitle);
        ImageIO.write(img,"png",selectedFile);
    }

    public void run() {
        if (Mode == SAVEASPNG)
        {
            try {
                saveAsPNG(ScreenTitle, FileSelected);
            } catch (IOException ex) {
                Logger.getLogger(ImageDriver.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InterruptedException ex) {
                Logger.getLogger(ImageDriver.class.getName()).log(Level.SEVERE, null, ex);
            } catch (AWTException ex) {
                Logger.getLogger(ImageDriver.class.getName()).log(Level.SEVERE, null, ex);
            }
        }else if (Mode == COPYTOCLIPBOARD){
            try {
                copyToClipboard(ScreenTitle);
            } catch (InterruptedException ex) {
                Logger.getLogger(ImageDriver.class.getName()).log(Level.SEVERE, null, ex);
            } catch (AWTException ex) {
                Logger.getLogger(ImageDriver.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    }
}
